[cherry-pick] 신규 회원 온보딩 모달 구현#689
Conversation
… 스토어 추가 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…컬 버그 6건 수정 - step-4: uploadImage 실패 시 close() 누락 → finally로 보장 - step-4: signUp 응답 accessToken 갱신 처리 추가 - step-4: isSubmitting 상태로 업로드 중 backdrop 닫힘 방지 - step-2: jobs 로딩 전 etcMode 오초기화 → useEffect+useRef로 수정 - step-1: 반복 이미지 선택 시 blob URL 메모리 누수 수정 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… Suspense 경계 추가 및 온보딩 트리거 분리 Next.js 15 빌드 경고 제거 및 SSR hydration 지연 방지 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…드 타이밍 버그 수정 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… 노출 버그 및 썸네일 업로드 의존성 제거 - journey-map: LOGIN_ONLY mock에 isFreeEnrolled: false 누락으로 스티키 결제 버튼이 노출되던 문제 수정 (LOGIN_ONLY는 미등록 상태이므로 isFreeEnrolled=false가 맞음) - study-helpers: fillStep2 썸네일 업로드 제거 — thumbnailFile은 optional 필드이며 스테이징 S3 업로드 타임아웃으로 그룹스터디 개설 E2E가 불안정하게 실패하던 원인 제거 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…업로드 S3 차단 및 step2 검증 복구 thumbnailExtension이 DEFAULT로 남아 '다음' 버튼이 비활성화되는 문제 수정. setInputFiles로 썸네일 확장자를 설정하되, S3 presigned URL PUT은 page.route()로 가로채 실제 업로드 없이 200 반환. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…임시 주석 처리 스테이징 환경 의존성 문제로 인해 @auth 개설 플로우 테스트 비활성화. 비로그인 UI 확인 테스트는 유지. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthrough온보딩 모달(4단계)과 상태 스토어를 추가하고, ClassPage 쿼리로 온보딩을 트리거하도록 통합했으며 E2E 썸네일 업로드 목킹과 테스트 조정, CSS 스페이싱 토큰 확장을 포함합니다. Changes온보딩 플로우 구현
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
e2e/group-study/create.spec.ts (1)
58-121:⚠️ Potential issue | 🟡 Minor | ⚡ Quick win주석 처리된
test.describe(...)대신test.describe.skip(...)로 비활성화 의도 명시
e2e/group-study/create.spec.ts에서그룹스터디 개설(58-121)과멘토스터디 개설(123-184) 스위트가/* ... */로 통째 주석 처리되어 있어 스킵 이력/의도가 드러나지 않습니다. 동일 의도라면test.describe.skip(...)로 변경해 운영 추적성을 확보해 주세요.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@e2e/group-study/create.spec.ts` around lines 58 - 121, The grouped test suites for "그룹스터디 개설" and "멘토스터디 개설" are fully commented out with a block comment; replace the block comment with explicit skips by converting the outer test.describe(...) blocks to test.describe.skip(...) so the intent and skip history are preserved; locate the suites that start with test.describe('그룹스터디 개설' ...) and test.describe('멘토스터디 개설' ...) and change their declarations to test.describe.skip(...) while keeping the inner tests and hooks unchanged.
🧹 Nitpick comments (3)
src/features/auth/model/use-oauth-redirect-controller.ts (1)
101-101: ⚡ Quick win신규 회원 리다이렉트 경로도 라우트 상수로 관리해주세요.
Line 101 하드코딩 문자열은 경로 변경 시 누락 위험이 있습니다. 기존
AUTH_ROUTE_PATHS패턴과 동일하게 상수화하는 게 유지보수에 유리합니다.💡 제안 패치
- router.replace('/class?onboarding=true'); + router.replace(AUTH_ROUTE_PATHS.CLASS_ONBOARDING);// src/features/auth/model/auth-route.ts export const AUTH_ROUTE_PATHS = { // ... CLASS_ONBOARDING: '/class?onboarding=true', } as const;🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/features/auth/model/use-oauth-redirect-controller.ts` at line 101, The router.replace('/class?onboarding=true') call in use-oauth-redirect-controller.ts uses a hardcoded path; add a CLASS_ONBOARDING entry to the existing AUTH_ROUTE_PATHS constant (e.g., CLASS_ONBOARDING: '/class?onboarding=true') in auth-route.ts, import AUTH_ROUTE_PATHS into use-oauth-redirect-controller.ts, and replace the hardcoded string with router.replace(AUTH_ROUTE_PATHS.CLASS_ONBOARDING) so the route is managed as a constant like the other auth routes.src/components/auth/modals/onboarding-modal/onboarding-modal.tsx (1)
3-3: ⚡ Quick win임의 회전 클래스 대신 명시 아이콘으로 교체해주세요.
Line 119의
rotate-[135deg]는 Tailwind arbitrary value라 가이드와 충돌합니다. 뒤로가기 아이콘을 직접 사용하면 규칙을 지키면서 의도가 더 명확해집니다.As per coding guidelines "`src/**/*.{ts,tsx,css}`: No Tailwind arbitrary values (`p-[4px]`, `w-[320px]`) — use project custom tokens from `global.css`".💡 제안 패치
-import { X } from 'lucide-react'; +import { ArrowLeft, X } from 'lucide-react'; @@ - <X className="h-300 w-300 rotate-[135deg]" /> + <ArrowLeft className="h-300 w-300" />Also applies to: 119-119
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/auth/modals/onboarding-modal/onboarding-modal.tsx` at line 3, The button currently uses the imported X icon with a Tailwind arbitrary rotate class (`rotate-[135deg]`) which violates project rules; replace that usage by importing and rendering an explicit back icon (e.g., ArrowLeft or ChevronLeft) from lucide-react and remove the `rotate-[135deg]` class and any related transform styles. Locate the `X` import and the JSX that applies `rotate-[135deg]` in onboarding-modal.tsx (component OnboardingModal) and update the import to the chosen back icon name and swap the rendered icon so the visual intent is preserved without arbitrary Tailwind values.src/components/auth/modals/onboarding-modal/steps/step-1-nickname.tsx (1)
115-115: ⚡ Quick win임의 폰트 크기 클래스는 토큰 클래스로 교체해주세요.
Line 115의
text-[48px]는 금지된 arbitrary value입니다.global.css에 정의된 타이포 토큰 클래스로 맞춰주세요.As per coding guidelines "
src/components/**/*.{ts,tsx}: Use custom Tailwind tokens fromsrc/app/global.css... Never use arbitrary pixel or color values likep-[4px],rounded-[8px]".🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/auth/modals/onboarding-modal/steps/step-1-nickname.tsx` at line 115, Replace the arbitrary Tailwind class text-[48px] on the emoji <span> in the Step1Nickname component (step-1-nickname.tsx) with the project's typography token from global.css; locate the span element containing "😊" and swap text-[48px] for the appropriate token class (e.g., the token that maps to 48px such as text-display-xl or whatever typography token your global.css defines) so no arbitrary pixel values remain.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/app/`(landing)/class/page.tsx:
- Around line 540-543: 현재 로직은 router.replace('/class')로 모든 쿼리를 지우므로 onboarding만
제거하도록 변경하세요: openOnboarding() 호출 후 searchParams를 기반으로 새로운 URLSearchParams(또는 기존
searchParams 복사)를 만들고 newParams.delete('onboarding')로 해당 키만 제거한 다음 쿼리 문자열이 비어있지
않으면 '?'+newParams.toString()를 붙여 router.replace(새로운경로) 호출하도록 교체하세요; 참조 심볼:
searchParams.get('onboarding'), openOnboarding(), router.replace('/class').
In `@src/components/auth/modals/onboarding-modal/onboarding-modal.tsx`:
- Around line 113-116: The header "back/close" buttons are still active during
submission; update the buttons that call handleBack (and the close button at the
other occurrence) to be disabled when isSubmitting to prevent interruptions: add
the disabled attribute and aria-disabled when isSubmitting, add a conditional
onClick (e.g. onClick={!isSubmitting ? handleBack : undefined}) or guard inside
handleBack to return early if isSubmitting, and update classes to reflect
disabled styling (remove hover/bg change and add pointer-events-none or a
disabled style) so both the back (handleBack) and close buttons are inert while
isSubmitting.
In `@src/components/auth/modals/onboarding-modal/steps/step-1-nickname.tsx`:
- Around line 196-200: The clickable consent container (the div around each
consent with key={consent.key}) is not keyboard accessible; update the element
used in the Step1 modal so it supports keyboard focus and activation: either
replace the div with a semantic <button> or add role="button", tabIndex={0}, and
an onKeyDown handler that invokes toggleConsent(consent.key as keyof Step1Data)
when Enter or Space is pressed; ensure the same change is applied to the other
consent block(s) around lines 201–211 so keyboard users can toggle consent using
toggleConsent.
---
Outside diff comments:
In `@e2e/group-study/create.spec.ts`:
- Around line 58-121: The grouped test suites for "그룹스터디 개설" and "멘토스터디 개설" are
fully commented out with a block comment; replace the block comment with
explicit skips by converting the outer test.describe(...) blocks to
test.describe.skip(...) so the intent and skip history are preserved; locate the
suites that start with test.describe('그룹스터디 개설' ...) and test.describe('멘토스터디
개설' ...) and change their declarations to test.describe.skip(...) while keeping
the inner tests and hooks unchanged.
---
Nitpick comments:
In `@src/components/auth/modals/onboarding-modal/onboarding-modal.tsx`:
- Line 3: The button currently uses the imported X icon with a Tailwind
arbitrary rotate class (`rotate-[135deg]`) which violates project rules; replace
that usage by importing and rendering an explicit back icon (e.g., ArrowLeft or
ChevronLeft) from lucide-react and remove the `rotate-[135deg]` class and any
related transform styles. Locate the `X` import and the JSX that applies
`rotate-[135deg]` in onboarding-modal.tsx (component OnboardingModal) and update
the import to the chosen back icon name and swap the rendered icon so the visual
intent is preserved without arbitrary Tailwind values.
In `@src/components/auth/modals/onboarding-modal/steps/step-1-nickname.tsx`:
- Line 115: Replace the arbitrary Tailwind class text-[48px] on the emoji <span>
in the Step1Nickname component (step-1-nickname.tsx) with the project's
typography token from global.css; locate the span element containing "😊" and
swap text-[48px] for the appropriate token class (e.g., the token that maps to
48px such as text-display-xl or whatever typography token your global.css
defines) so no arbitrary pixel values remain.
In `@src/features/auth/model/use-oauth-redirect-controller.ts`:
- Line 101: The router.replace('/class?onboarding=true') call in
use-oauth-redirect-controller.ts uses a hardcoded path; add a CLASS_ONBOARDING
entry to the existing AUTH_ROUTE_PATHS constant (e.g., CLASS_ONBOARDING:
'/class?onboarding=true') in auth-route.ts, import AUTH_ROUTE_PATHS into
use-oauth-redirect-controller.ts, and replace the hardcoded string with
router.replace(AUTH_ROUTE_PATHS.CLASS_ONBOARDING) so the route is managed as a
constant like the other auth routes.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 47676be1-728a-43cb-bcc6-e2c6267a35a4
⛔ Files ignored due to path filters (1)
public/onboarding/mascot.pngis excluded by!**/*.png
📒 Files selected for processing (12)
e2e/class/journey-map.spec.tse2e/group-study/create.spec.tse2e/support/study-helpers.tssrc/app/(landing)/class/page.tsxsrc/app/global.csssrc/components/auth/modals/onboarding-modal/onboarding-modal.tsxsrc/components/auth/modals/onboarding-modal/steps/step-1-nickname.tsxsrc/components/auth/modals/onboarding-modal/steps/step-2-job.tsxsrc/components/auth/modals/onboarding-modal/steps/step-3-goals.tsxsrc/components/auth/modals/onboarding-modal/steps/step-4-completion.tsxsrc/features/auth/model/use-oauth-redirect-controller.tssrc/stores/use-onboarding-store.ts
…st·접근성 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/components/auth/modals/onboarding-modal/steps/step-1-nickname.tsx (1)
196-201: ⚡ Quick win
CONSENTS.map의 key/타입 처리 가이드라인을 맞춰주세요.Line 200의
as keyof Step1Data는 런타임 가드 없는 단언이고, Line 196의 key도 팀 규칙의?? index패턴과 다릅니다.권장 패치
+type ConsentKey = 'termsAgreed' | 'privacyAgreed' | 'marketingAgreed'; + -const CONSENTS = [ +const CONSENTS: Array<{ key: ConsentKey; label: string; link: string }> = [ { key: 'termsAgreed' as const, @@ -const toggleConsent = (key: keyof Step1Data) => { +const toggleConsent = (key: ConsentKey) => { updateData(key, !data[key]); }; @@ - {CONSENTS.map((consent) => ( - <div key={consent.key} className="flex items-center gap-150"> + {CONSENTS.map((consent, index) => ( + <div key={consent.key ?? index} className="flex items-center gap-150"> @@ - onClick={() => toggleConsent(consent.key as keyof Step1Data)} + onClick={() => toggleConsent(consent.key)} >As per coding guidelines, "Use the nullish coalescing operator (
??) with index fallback when using array.map()for React keys" 및 "Never use bareasassertions without runtime guards" 규칙을 근거로 했습니다.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/auth/modals/onboarding-modal/steps/step-1-nickname.tsx` around lines 196 - 201, When mapping CONSENTS, use an index fallback for the React key and add a runtime guard before casting the consent key to Step1Data: change the map signature to CONSENTS.map((consent, idx) => ...) and set the element key to consent.key ?? idx; implement a small type guard function like isStep1DataKey(k: string | undefined): k is keyof Step1Data and use it in the onClick handler to check the consent.key (or computed fallback) before calling toggleConsent(consentKey); if the guard fails, skip or log a warning instead of using a bare as assertion. Ensure you reference CONSENTS, Step1Data, toggleConsent, and the new isStep1DataKey guard in the fix.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@src/components/auth/modals/onboarding-modal/steps/step-1-nickname.tsx`:
- Around line 196-201: When mapping CONSENTS, use an index fallback for the
React key and add a runtime guard before casting the consent key to Step1Data:
change the map signature to CONSENTS.map((consent, idx) => ...) and set the
element key to consent.key ?? idx; implement a small type guard function like
isStep1DataKey(k: string | undefined): k is keyof Step1Data and use it in the
onClick handler to check the consent.key (or computed fallback) before calling
toggleConsent(consentKey); if the guard fails, skip or log a warning instead of
using a bare as assertion. Ensure you reference CONSENTS, Step1Data,
toggleConsent, and the new isStep1DataKey guard in the fix.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 2b36a5fa-c643-48e5-b2bf-4fde66d60cb4
📒 Files selected for processing (5)
src/app/(landing)/class/page.tsxsrc/components/auth/modals/onboarding-modal/onboarding-modal.tsxsrc/components/auth/modals/onboarding-modal/steps/step-1-nickname.tsxsrc/components/auth/modals/onboarding-modal/steps/step-4-completion.tsxsrc/components/common/ui/editor/markdown-editor.tsx
✅ Files skipped from review due to trivial changes (1)
- src/components/common/ui/editor/markdown-editor.tsx
개요
신규 OAuth 가입 완료 후 프로필 설정(닉네임·직무·목표·약관 동의)을 유도하는 4단계 온보딩 모달을 구현한다.
createPortal기반으로 렌더링하고 Zustand로 전역 열림 상태를 관리한다./class?onboarding=true쿼리 파라미터를 진입점으로 사용해 기존 OAuth 플로우를 최소 수정했다.원본 PR
feat/onBoardingCherry-pick 대상 커밋
dd88bd5— feat(store): 온보딩 모달 Zustand 스토어 추가208fefc— fix(onboarding): 모달 4단계 크리티컬 버그 6건 수정907e059— fix(class): useSearchParams Suspense 경계 추가 및 온보딩 트리거 분리e0e64a9— JPEG MIME 누락·noopener 미적용·업로드 타이밍 버그 수정0ca3fd4— OAuth 신규 회원 온보딩 플로우 리다이렉트 연결b0ae6d7— fix(e2e): LOGIN_ONLY 결제 CTA 노출 버그 및 썸네일 업로드 의존성 제거7bd892d— fix(e2e): 그룹스터디 개설 테스트 썸네일 업로드 S3 차단 및 step2 검증 복구62ef978— test(e2e): 그룹/멘토스터디 개설 테스트 임시 주석 처리변경 파일
src/stores/use-onboarding-store.ts— 온보딩 모달 open/close Zustand 스토어src/components/auth/modals/onboarding-modal/onboarding-modal.tsx— 4단계 모달 컨테이너src/components/auth/modals/onboarding-modal/steps/step-1-nickname.tsx— 닉네임·이미지·약관·경력src/components/auth/modals/onboarding-modal/steps/step-2-job.tsx— 직무 선택src/components/auth/modals/onboarding-modal/steps/step-3-goals.tsx— 학습 목표 선택src/components/auth/modals/onboarding-modal/steps/step-4-completion.tsx— 최종 제출src/app/(landing)/class/page.tsx— 온보딩 트리거 및 Suspense 경계src/features/auth/model/use-oauth-redirect-controller.ts— OAuth 리다이렉트 연결src/app/global.css— spacing 토큰 2개 추가public/onboarding/mascot.png— 완료 화면 마스코트 이미지e2e/class/journey-map.spec.ts— LOGIN_ONLY mock isFreeEnrolled 버그 수정e2e/support/study-helpers.ts— 썸네일 업로드 의존성 제거e2e/group-study/create.spec.ts— S3 업로드 차단 mock + 개설 테스트 임시 비활성화혼입 검증 결과
cherry-pick 대상 8개 커밋이 수정하는 파일이 PR #685 변경 파일 목록과 정확히 일치함.
브랜치 전체 diff(
feat/onBoardingvsmain)는 244개 파일이나, 이는 develop에서 축적된 다른 feature 커밋이며 cherry-pick 범위에 포함되지 않음.Test plan
/class?onboarding=true진입 → 모달 자동 오픈?onboarding=trueURL 파라미터 제거🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Tests
Style